package com.hydra.baseui.recyclerlist;

import android.util.Log;
import android.util.SparseArray;
import android.view.View;
import android.view.ViewGroup;
import androidx.recyclerview.widget.RecyclerView;
import androidx.recyclerview.widget.RecyclerView.AdapterDataObserver;
import androidx.recyclerview.widget.RecyclerView.ViewHolder;
import java.util.ArrayList;
import java.util.Random;

/**
 * Created by Administrator on 2016/7/11.
 *
 */
public class RecyclerHeaderListAdapter extends RecyclerView.Adapter {

    private static final int HEADER_FOOTER_ITEM_RANDOM_BASE = 1989;  //随便取的，一个随机数的base
    private static final int HEADER_FOOTER_ITEM_TYPE_BASE = Integer.MIN_VALUE + HEADER_FOOTER_ITEM_RANDOM_BASE;
    private static final long HEADER_FOOTER_ITEM_ID_BASE = Long.MIN_VALUE + HEADER_FOOTER_ITEM_RANDOM_BASE;

    protected static class RecycleHeaderFooterInfo {

        public View view;
        public int type;
        public long uniqueId;

        @Override
        public boolean equals(Object o) {
            if(o == null || !(o instanceof RecycleHeaderFooterInfo)) {
                return false;
            }

            RecycleHeaderFooterInfo other = (RecycleHeaderFooterInfo) o;

            return type == other.type && uniqueId == other.uniqueId && view == other.view;
        }

        @Override
        public int hashCode() {
            return type;
        }
    }

    /**
     * final类型，不能动态设置
     */
    private final RecyclerView.Adapter mAdapter;

    private AdapterDataObserver mWrappedObserver = new AdapterDataObserver() {
        @Override
        public void onChanged() {
            notifyDataSetChanged();
        }

        @Override
        public void onItemRangeChanged(int positionStart, int itemCount) {
            notifyItemRangeChanged(positionStart + getHeadersCount(), itemCount);
        }

        @Override
        public void onItemRangeInserted(int positionStart, int itemCount) {
            notifyItemRangeInserted(positionStart + getHeadersCount(), itemCount);
        }

        @Override
        public void onItemRangeRemoved(int positionStart, int itemCount) {
            notifyItemRangeRemoved(positionStart + getHeadersCount(), itemCount);
        }

        @Override
        public void onItemRangeMoved(int fromPosition, int toPosition, int itemCount) {
            notifyItemMoved(fromPosition + getHeadersCount(), toPosition + getHeadersCount());
        }
    };

    /**
     * 在adapter的不断addHeader或footer过程中，尽量不出现itemType相同的两个
     * 不让任何两个header和footer的type相同
     */
    private int mHeaderFooterTypeBase;

    /**
     * 不让任何两个header和footer的id相同
     */
    private long mHeaderFooterUniqueIdBase;

    protected ArrayList<RecycleHeaderFooterInfo> mHeaderViewInfos = new ArrayList<RecycleHeaderFooterInfo>();
    protected ArrayList<RecycleHeaderFooterInfo> mFooterViewInfos = new ArrayList<RecycleHeaderFooterInfo>();
    protected SparseArray<RecycleHeaderFooterInfo> mHeaderFooterTypeMap = new SparseArray<RecycleHeaderFooterInfo>(10);

    RecyclerHeaderListAdapter(RecyclerView.Adapter adapter) {
        Random random = new Random();

        mHeaderFooterTypeBase = HEADER_FOOTER_ITEM_TYPE_BASE + random.nextInt(HEADER_FOOTER_ITEM_RANDOM_BASE);
        mHeaderFooterUniqueIdBase = HEADER_FOOTER_ITEM_ID_BASE + random.nextInt(HEADER_FOOTER_ITEM_RANDOM_BASE);

        mAdapter = adapter;

        if (mAdapter != null) {
            setHasStableIds(mAdapter.hasStableIds());

            mAdapter.registerAdapterDataObserver(mWrappedObserver);
        }
    }

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        RecycleHeaderFooterInfo info = mHeaderFooterTypeMap.get(viewType);

        if(info != null) {
            return new BaseItemHolder(info.view);
        } else {
            return mAdapter.onCreateViewHolder(parent, viewType);
        }
    }

    /**
     * header和footer不动态更新
     */
    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
        int numHeaders = getHeadersCount();

        if(position >= numHeaders) {
            final int adjPosition = position - numHeaders;

            if (mAdapter != null) {
                if (adjPosition < mAdapter.getItemCount()) {
                    mAdapter.onBindViewHolder(holder, adjPosition);
                }
            }
        }
    }

    public void release() {
        if (mAdapter != null) {
            try {
                mAdapter.unregisterAdapterDataObserver(mWrappedObserver);
            } catch (IllegalStateException e) {
                Log.e(getClass().getSimpleName(), "wrapped adapter unregisterAdapterDataObserver failed : " + e);
            }
        }

        mHeaderFooterTypeMap.clear();

        mHeaderViewInfos.clear();
        mFooterViewInfos.clear();
    }

    @Override
    public long getItemId(int position) {
        // Header (negative positions will throw an IndexOutOfBoundsException)
        int numHeaders = getHeadersCount();
        if (position < numHeaders) {
            return mHeaderViewInfos.get(position).uniqueId;
        }

        // Adapter
        final int adjPosition = position - numHeaders;
        int adapterCount = 0;
        if (mAdapter != null) {
            adapterCount = mAdapter.getItemCount();
            if (adjPosition < adapterCount) {
                return mAdapter.getItemId(adjPosition);
            }
        }

        // Footer (off-limits positions will throw an IndexOutOfBoundsException)
        return mFooterViewInfos.get(adjPosition - adapterCount).uniqueId;
    }

    protected long newHeaderFooterUniqueId() {
        return mHeaderFooterUniqueIdBase++;
    }

    public void addHeaderView(int index, View view) {
        RecycleHeaderFooterInfo info = buildHeaderOrFooter(view);

        mHeaderViewInfos.add(index, info);

        mHeaderFooterTypeMap.put(info.type, info);

        notifyItemRangeInserted(index, 1);
    }

    public void addHeaderView(View view) {
        addHeaderView(getHeadersCount(), view);
    }

    public void removeHeaderView(View view) {
        int headerSize = mHeaderViewInfos.size();

        for(int i = 0; i < headerSize; i++) {
            RecycleHeaderFooterInfo info = mHeaderViewInfos.get(i);

            if(info.view == view) {
                mHeaderViewInfos.remove(info);

                mHeaderFooterTypeMap.remove(info.type);

                notifyItemRangeRemoved(i, 1);

                return;
            }
        }
    }

    public void addFooterView(int index, View view) {
        RecycleHeaderFooterInfo info = buildHeaderOrFooter(view);

        mFooterViewInfos.add(index, info);

        mHeaderFooterTypeMap.put(info.type, info);

        notifyItemRangeInserted(index + getHeadersCount() + (mAdapter == null ? 0 : mAdapter.getItemCount()), 1);
    }

    public void addFooterView(View view) {
        addFooterView(getFootersCount(), view);
    }

    public void removeFooterView(View view) {
        int footerSize = mFooterViewInfos.size();

        for(int i = 0; i < footerSize; i++) {
            RecycleHeaderFooterInfo info = mFooterViewInfos.get(i);

            if(info.view == view) {
                mFooterViewInfos.remove(info);

                mHeaderFooterTypeMap.remove(info.type);

                notifyItemRangeRemoved(i + getHeadersCount() + (mAdapter == null ? 0 : mAdapter.getItemCount()), 1);

                return;
            }
        }
    }

    protected RecycleHeaderFooterInfo buildHeaderOrFooter(View view) {
        RecycleHeaderFooterInfo info = new RecycleHeaderFooterInfo();

        info.view = view;
        info.type = newHeaderFooterType();
        info.uniqueId = newHeaderFooterUniqueId();

        return info;
    }

    protected int newHeaderFooterType() {
        return mHeaderFooterTypeBase++;
    }

    public RecyclerView.Adapter getWrappedAdapter() {
        return mAdapter;
    }

    @Override
    public int getItemViewType(int position) {
        // Header (negative positions will throw an IndexOutOfBoundsException)
        int numHeaders = getHeadersCount();
        if (position < numHeaders) {
            return mHeaderViewInfos.get(position).type;
        }

        // Adapter
        final int adjPosition = position - numHeaders;
        int adapterCount = 0;
        if (mAdapter != null) {
            adapterCount = mAdapter.getItemCount();
            if (adjPosition < adapterCount) {
                return mAdapter.getItemViewType(adjPosition);
            }
        }

        // Footer (off-limits positions will throw an IndexOutOfBoundsException)
        return mFooterViewInfos.get(adjPosition - adapterCount).type;
    }

    @Override
    public int getItemCount() {
        if (mAdapter != null) {
            return getFootersCount() + getHeadersCount() + mAdapter.getItemCount();
        } else {
            return getFootersCount() + getHeadersCount();
        }
    }

    public int getHeadersCount() {
        return mHeaderViewInfos.size();
    }

    public int getFootersCount() {
        return mFooterViewInfos.size();
    }

    @Override
    public void setHasStableIds(boolean hasStableIds) {
        super.setHasStableIds(hasStableIds);

        if (mAdapter != null && !mAdapter.hasObservers()) {
            mAdapter.setHasStableIds(hasStableIds);
        }
    }

    @Override
    public void onViewRecycled(ViewHolder holder) {
        super.onViewRecycled(holder);

        if (mAdapter != null && mHeaderFooterTypeMap.get(holder.getItemViewType()) == null) {
            mAdapter.onViewRecycled(holder);
        }
    }

    @Override
    public boolean onFailedToRecycleView(ViewHolder holder) {
        if (mAdapter != null && mHeaderFooterTypeMap.get(holder.getItemViewType()) == null) {
            return mAdapter.onFailedToRecycleView(holder);
        }

        return super.onFailedToRecycleView(holder);
    }

    @Override
    public void onViewAttachedToWindow(ViewHolder holder) {
        super.onViewAttachedToWindow(holder);

        if (mAdapter != null && mHeaderFooterTypeMap.get(holder.getItemViewType()) == null) {
            mAdapter.onViewAttachedToWindow(holder);
        }
    }

    @Override
    public void onViewDetachedFromWindow(ViewHolder holder) {
        super.onViewDetachedFromWindow(holder);

        if (mAdapter != null && mHeaderFooterTypeMap.get(holder.getItemViewType()) == null) {
            mAdapter.onViewDetachedFromWindow(holder);
        }
    }

    @Override
    public void onAttachedToRecyclerView(RecyclerView recyclerView) {
        super.onAttachedToRecyclerView(recyclerView);

        if (mAdapter != null) {
            mAdapter.onAttachedToRecyclerView(recyclerView);
        }
    }

    @Override
    public void onDetachedFromRecyclerView(RecyclerView recyclerView) {
        super.onDetachedFromRecyclerView(recyclerView);

        release();

        if (mAdapter != null) {
            mAdapter.onDetachedFromRecyclerView(recyclerView);
        }
    }
}
